﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Text.RegularExpressions;
using System.IO;
using System.Threading;
using System.Diagnostics;

namespace BBSPicturesDownload
{

    public partial class BBSPicturesDownload : Form
    {
        private String m_domain = String.Empty;

        private Dictionary<int, String> m_allIndexPageUrls = new Dictionary<int, string>();
        private Dictionary<string, string> m_allThreadPageUrls = new Dictionary<string, string>();
        private Dictionary<string, string> m_allPictureUrls = new Dictionary<string, string>();

        public BBSPicturesDownload()
        {
            InitializeComponent();
        }

        private void BrowseButton_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dialog = new FolderBrowserDialog();
            if (DialogResult.OK == dialog.ShowDialog())
            {
                SavePathTextBox.Text = dialog.SelectedPath;
            }
        }
        private void DownloadButton_Click(object sender, EventArgs e)
        {
            Test();
            UsingBackGroundThread();
        }
        private void addFiltersButton_Click(object sender, EventArgs e)
        {
            if (!String.IsNullOrEmpty(filterTextBox.Text))
                FilterListBox.Items.Add(filterTextBox.Text);
        }

        private bool ValidateInputs()
        {
            int startNumber = 0;
            int endNumber = 0;

            if (!string.IsNullOrEmpty(InitialIndexPageUrlTextBox.Text)
                && !String.IsNullOrEmpty(SavePathTextBox.Text)
                && !String.IsNullOrEmpty(threadRegrexTextBox.Text)
                && !String.IsNullOrEmpty(StartNumberTextBox.Text)
                && !String.IsNullOrEmpty(EndNumberTextBox.Text)
                && !String.IsNullOrEmpty(maxSecondsTextBox.Text)
                && int.TryParse(StartNumberTextBox.Text, out startNumber)
                && int.TryParse(EndNumberTextBox.Text, out endNumber)
                && startNumber <= endNumber)
            {                
                return true;
            }
            else
            {
                MessageBox.Show("输入错误！请重新输入");
                return false;
            }   
        }
        private void GetDomain()
        {
            String initialIndexPageUrl = InitialIndexPageUrlTextBox.Text;
            m_domain = initialIndexPageUrl.Substring(0, initialIndexPageUrl.IndexOf('/', 8) + 1);
        }
        private void GetIndexPageUrls()
        {
            int startNumber = 0;
            int endNumber = 0;
            String initialIndexPageUrl = InitialIndexPageUrlTextBox.Text;
            int.TryParse(StartNumberTextBox.Text, out startNumber);
            int.TryParse(EndNumberTextBox.Text, out endNumber);

            for (int i = startNumber; i <= endNumber; ++i)
            {
                string url = string.Empty;
                url = initialIndexPageUrl.Replace("XXXXX", i.ToString());
                if(!m_allIndexPageUrls.ContainsKey(i))
                    m_allIndexPageUrls.Add(i, url);
            }
        }
        private void GetThreadPageUrlsByIndex(int index, string indexPageUrl)
        {
            String content = String.Empty;
            try
            {
                WebClient webClient = new WebClient();
                content = webClient.DownloadString(indexPageUrl);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Assert(false);
            }

            if (String.IsNullOrEmpty(content))
                return;

            Regex re = new Regex("<a[\\s]+[^>]*?href[\\s]?=[\\s\\\"\\']+(.*?)[\\\"\\']+.*?>([^<]+|.*?)?<\\/a>", RegexOptions.None);
            MatchCollection mc = re.Matches(content);
            foreach (Match ma in mc)
            {
                string threadUrl = ma.Value;
                Regex r = new Regex(threadRegrexTextBox.Text); 
                Match m = r.Match(threadUrl);
                if (m.Success)
                {
                    // find title
                    int startIndex = ma.Value.IndexOf('>',0);
                    int endIndex = threadUrl.IndexOf('<', startIndex);
                    int length = endIndex - startIndex -1; 
                    if(length <= 0)
                        continue;

                    String threadTitle = String.Empty;
                    threadTitle = threadUrl.Substring(startIndex + 1, length);
                    threadTitle = DeleteInvalidCharsForPath(threadTitle);
                    threadTitle = index.ToString() + threadTitle;

                    // find url
                    string threadSubUrl = m.Value;

                    // add to dictionary
                    if (!m_allThreadPageUrls.ContainsKey(threadTitle) && !string.IsNullOrEmpty(threadTitle) && threadTitle.Length >= 8)
                        m_allThreadPageUrls.Add(threadTitle, m_domain + threadSubUrl.Replace("&amp;","&"));
                }
            }
        }
        private void GetThreadPageUrls()
        {
            foreach(System.Collections.Generic.KeyValuePair<int, String> keyValue in m_allIndexPageUrls)           
            {
                String indexUrl = keyValue.Value;
                if (String.IsNullOrEmpty(indexUrl))
                    continue;
                GetThreadPageUrlsByIndex(keyValue.Key, indexUrl);
            }
        }
        private void GetPictureUrlsByThread(string threadTitle, string threadPageUrl)
        {
            string content = String.Empty;
            try
            {
                WebClient webClient = new WebClient();
                content = webClient.DownloadString(threadPageUrl);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.Assert(false);
            }

            if(String.IsNullOrEmpty(content))
                return;

            Regex re = new Regex("<img\\s+src=[\"']+(.*?)(.jpg)[\"']+", RegexOptions.None);
            MatchCollection mc = re.Matches(content);
            foreach (Match ma in mc)
            {
                string pictureUrl = ma.Value;

                // filter 
                foreach (String str in FilterListBox.Items)
                {
                    if (pictureUrl.Contains(str))
                        return;
                }

                int startIndex = pictureUrl.IndexOf('\"');
                int endIndex = pictureUrl.IndexOf('\"', startIndex + 1);
                int length = endIndex - startIndex - 1;
                if(length <= 0)
                    continue;
                pictureUrl = pictureUrl.Substring(startIndex + 1, length);

                if (!m_allPictureUrls.ContainsKey(pictureUrl))
                {
                    int eIndex = pictureUrl.LastIndexOf('.');
                    int sIndex = pictureUrl.LastIndexOf('/');
                    int l = eIndex - sIndex - 1;
                    if(l<=0)
                        continue;
                    string name = pictureUrl.Substring(sIndex + 1, l);
                    name = DeleteInvalidCharsForPath(name);
                    m_allPictureUrls.Add(pictureUrl, SavePathTextBox.Text + "\\" + threadTitle + "\\"+ name + ".jpg");
                }
            }
        }
        private void GetPictureUrls()
        {
            foreach (System.Collections.Generic.KeyValuePair<String, String> keyValue in m_allThreadPageUrls)
            {
                GetPictureUrlsByThread(keyValue.Key, keyValue.Value);
            }
        }
        private void DownLoadPicture(string url, string path)
        {
            int index = path.LastIndexOf('\\');
            if (index < 0)
                return;
            String directory = path.Substring(0, index);
            ValidatePath(directory);
            if (File.Exists(path))
            {
                toolStripStatusLabel1.Text = "文件" + path + "已经存在。。。";
                return;
            }

            try
            {
                HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create(url);
                int max = 4;
                int.TryParse(maxSecondsTextBox.Text,out max);
                //hwr.AuthenticationLevel = System.Net.Security.AuthenticationLevel.None;
                //hwr.UnsafeAuthenticatedConnectionSharing = true;
                //hwr.UseDefaultCredentials = true;
                hwr.ReadWriteTimeout = max * 1000;
                WebResponse wr = hwr.GetResponse();
                using (Stream stream = wr.GetResponseStream())
                {
                    Image img = Image.FromStream(stream);
                    img.Save(path);
                    stream.Close();
                    toolStripStatusLabel1.Text = "文件" + path + "下载完成。。。";
                }
            }
            catch(Exception e)
            {
                System.Diagnostics.Debug.Assert(false);
                toolStripStatusLabel1.Text = "文件" + path + "下载失败。。。";
            }
        }
        private void DownLoadPictures()
        {
            foreach (System.Collections.Generic.KeyValuePair<String, String> keyValue in m_allPictureUrls)
            {
                DownLoadPicture(keyValue.Key, keyValue.Value);
            }
        }

        private void DoAll()
        {
            toolStripStatusLabel1.Text = "准备中...";

            // step0 
            // 验证输入
            if (!ValidateInputs())
                return;

            // step1
            // 获取域名
            toolStripStatusLabel1.Text = "获取域名...";
            GetDomain();

            // step2
            // 得到所有的索引页urls
            toolStripStatusLabel1.Text = "正在获取索引页urls...";
            GetIndexPageUrls();

            // step3
            // 得到所有帖子标题和urls
            toolStripStatusLabel1.Text = "共获得"+ m_allIndexPageUrls.Count + "索引页，"+"正在获取帖子urls...";
            GetThreadPageUrls();

            // step4
            // 得到所有图片的urls
            toolStripStatusLabel1.Text = "共获得" + m_allThreadPageUrls.Count + "帖子，" + "正在获取图片的urls...";
            GetPictureUrls();

            // step5
            // 下载所有图片
            toolStripStatusLabel1.Text = "共获得" + m_allPictureUrls.Count + "图片，" + "开始下载图片...";
            DownLoadPictures();

            toolStripStatusLabel1.Text = "完成下载...";
        }
        private void UsingBackGroundThread()
        {
            Thread thread = new Thread( new ThreadStart(DoAll));
            thread.IsBackground=true;
            thread.Start( ); 
        }

        private void ValidatePath(String directory)
        {
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }
        }
        private String DeleteInvalidCharsForPath(String threadTitle)
        {
            threadTitle = threadTitle.Replace('?', 'A');
            threadTitle = threadTitle.Replace('\\', 'A');
            threadTitle = threadTitle.Replace('/', 'A');
            threadTitle = threadTitle.Replace(':', 'A');
            threadTitle = threadTitle.Replace('*', 'A');
            threadTitle = threadTitle.Replace('"', 'A');
            threadTitle = threadTitle.Replace('<', 'A');
            threadTitle = threadTitle.Replace('>', 'A');
            threadTitle = threadTitle.Replace('|', 'A');
            return threadTitle;
        }
        
        [Conditional("DEBUG")]
        private void Test()
        {
            GetPictureUrlsByThread("test", "http://www.shdf007.com/viewthread.php?tid=6956&extra=page%3D37");
            DownLoadPicture("http://www.8bar8.com/Fashion1216/Mon_0712/57_586733_5af8044d2be9ff4.jpg", "e:\\图片\\test.jpg");
        }
    }
}
